package com.lnj.config;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.lnj.bean.dto.ProductDTO;
import com.lnj.service.ToolServices;
import com.lnj.utils.ProductContentRetriever;
import com.lnj.utils.ProductVectorDTO;
import dev.langchain4j.community.model.dashscope.QwenEmbeddingModel;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentParser;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.TextDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentByLineSplitter;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.*;
import dev.langchain4j.service.tool.ToolProvider;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.elasticsearch.ElasticsearchEmbeddingStore;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import org.apache.poi.ss.usermodel.*;
import org.jspecify.annotations.NonNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.InputStream;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


@Configuration
public class AiConfig {
    //带记忆、区分用户、支持流式会话
    public interface Assistant {
        @SystemMessage("""
        你是一位电商网站的客服，名字叫小李北。你的职责是:
        1. 根据商品向量库中的信息，向用户推荐合适的商品
        2. 回答用户关于商品的详细问题
        3. 保持友好专业的服务态度
        4. 如果用户询问的商品不在库中，如实告知并推荐类似商品
        5. 当用户询问商品详情时，请从商品向量库中获取准确信息
        6. 对于商品价格、库存等具体信息，请使用getProductInfoById工具查询
        7. 当用户需要购买商品时，要求用户输入商品ID和购买数量
        8. 确认订单信息后，调用createOrder工具创建订单
        9. 订单创建成功后，返回订单号并通知用户
        10. 保持与用户的持续互动，解决用户问题并提供支持
        """)
        String chat(@MemoryId String memoryId, @UserMessage String question);

        @SystemMessage("""
        你是一位电商网站的客服，名字叫小李北。你的职责是:
        1. 根据商品向量库中的信息，向用户推荐合适的商品
        2. 回答用户关于商品的详细问题
        3. 保持友好专业的服务态度
        4. 如果用户询问的商品不在库中，如实告知并推荐类似商品
        5. 当用户询问商品详情时，请从商品向量库中获取准确信息
        6. 对于商品价格、库存等具体信息，请使用getProductInfoById工具查询
        """)
        TokenStream chatStream(@MemoryId String memoryId, @UserMessage String question); //需要有一个StreamingChatModel

    }

    @Bean
    public ProductContentRetriever productContentRetriever(
            ElasticsearchEmbeddingStore embeddingStore,
            QwenEmbeddingModel qwenEmbeddingModel) {
        return new ProductContentRetriever(embeddingStore, qwenEmbeddingModel);
    }

    @Value("${langchain4j.community.dashscope.api-key}")
    private String dashScopeApiKey;

    @Bean
    public QwenEmbeddingModel qwenEmbeddingModel() {
        return QwenEmbeddingModel.builder()
                .apiKey(dashScopeApiKey)
                .modelName("text-embedding-v1") // 使用合适的嵌入模型名称
                .build();
    }


    /**
     *
     * @param chatModel  非流式 AI 聊天模型（如 OpenAI 的 ChatGPT）
     * @param streamingChatModel 流式AI聊天模型（支持实时流式响应）
     * @param chatMemoryStore 聊天记忆存储（用于持久化对话历史）
     */
    @Bean   // 生成代理类对象，这个对象要被spring托管 ->才能注入到Controller
    public Assistant assistant(ChatModel chatModel,
                               StreamingChatModel streamingChatModel,
                               ChatMemoryStore chatMemoryStore, ToolServices tools,
                               EmbeddingStore embeddingStore,ProductContentRetriever productContentRetriever,
                               QwenEmbeddingModel qwenEmbeddingModel,
                               ToolProvider toolProvider){

//        PersistentChatMemoryStore persistentChatMemoryStore = new PersistentChatMemoryStore();
        //每次对话创建一个独立的记忆窗口，存储历史消息，支持上下文关联
        ChatMemoryProvider chatMemoryProvider= memoryId-> MessageWindowChatMemory.builder()
                .id(   memoryId )
                .maxMessages(1000)
                .chatMemoryStore(   chatMemoryStore )
                .build();

        //使用 Assistant 接口动态生成一个代理类 处理 AI 模型调用、记忆管理、流式响应
        Assistant assistant= AiServices.builder(Assistant.class)
                .chatModel(  chatModel )
                .streamingChatModel( streamingChatModel  )
                .chatMemoryProvider(  chatMemoryProvider )
                .tools(  tools )    //工具
                .toolProvider(toolProvider ) // 工具提供器
                .contentRetriever(productContentRetriever) // 内容检索器
                .build();
        return assistant;
     }

//    @Bean
//    public InMemoryEmbeddingStore embeddingStore() {
//        List<Document> documents = FileSystemDocumentLoader.loadDocuments("E:\\testdocuments");
//        InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
//        EmbeddingStoreIngestor.ingest(documents, embeddingStore);
//
//       return embeddingStore;
//    }

    //初始化向量数据库 Elasticsearch
    @Bean
    public CommandLineRunner initData(ElasticsearchClient elasticsearchClient,
                                      ElasticsearchEmbeddingStore embeddingStore, QwenEmbeddingModel qwenEmbeddingModel) {
        return args -> {
            SearchResponse<ProductDTO> response = elasticsearchClient.search(s -> s
                            .index("products")
                            .query(q -> q
                                    .bool(b -> b
                                            .filter(f -> f
                                                    .term(t -> t
                                                            .field("productStatus")
                                                            .value(1)
                                                    )
                                            )
                                    )
                            )
                            .size(10000), // Adjust size based on your needs
                    ProductDTO.class
            );

            List<ProductDTO> products = response.hits().hits().stream()
                    .map(hit -> {
                        ProductDTO dto = hit.source();
                        // You might need to set additional fields from hit if needed
                        return dto;
                    })
                    .collect(Collectors.toList());

            // 将ProductVectorDTO对象转换为TextSegment和Embedding并存储到Elasticsearch
            List<TextSegment> segments = new ArrayList<>();
            List<Embedding> embeddings = new ArrayList<>();

            for (ProductDTO product : products) {
                // 将ProductVectorDTO转换为文本表示
                String productText = convertProductToText(product);
                System.out.println(productText);
                TextSegment segment = TextSegment.from(productText);
                segments.add(segment);

                // 对文本进行向量化处理
                Embedding embedding = qwenEmbeddingModel.embed(productText).content();
                embeddings.add(embedding);
            }

            // 存储到 Elasticsearch
            embeddingStore.addAll(embeddings, segments);
            System.out.printf("已初始化向量：%d 条%n", embeddings.size());
        };
    }

    private String convertProductToText(ProductDTO productVector) {
        // 根据你的需求，将ProductVectorDTO对象转换为适合向量化的文本格式
        // 示例格式：
        return String.format(
                "商品ID: %d, 商品名称向量: %s, 分类名称向量: %s, 商品详情向量: %s, 原价向量: %s, 现价向量: %s",
                productVector.getProductId(),
                productVector.getProductName(),
                productVector.getCategoryName(),
                productVector.getDetail(),
                productVector.getOriginalPrice(),
                productVector.getPrice()
        );
    }


}
